#!/usr/bin/env node

/* 命令行交互工具 */
const prompts = require('prompts')
/* 进度条 */
const ProgressBar = require('progress');
/* 输出文本带样式 */
const chalk = require('chalk');
const { log } = require('console')
const fs = require('fs')
const path = require('path');
const basePath = path.resolve(__dirname, './')



/* 获取文件相关选项 */
const getAppOptions = async () => {
    const { appName } = await prompts([{
        type: 'text',
        name: 'appName',
        message: '请输入应用名称',
        validate: value =>
            !/^[a-zA-Z0-9\-/_]{1,}$/.test(value) ? '请输入正确的文件名' : true
    },
        // TODO 等待完善 所需模板文件
        // {
        //     type: 'multiselect',
        //     name: 'package',
        //     message: '选择所需依赖,空格确定选择，↑ 向上选择，↓ 向下选择，enter 确认',
        //     choices: [
        //         { title: 'typescript', description: '将采用typescript进行开发', value: 'typescript' },
        //         { title: 'apidoc', description: '可以通过npm run apidoc生成api文档', value: 'apidoc' },
        //         { title: 'sequelize', description: '是 Node 的一个 ORM(Object-Relational Mapping) 框架，用来方便数据库操作。', value: 'sequelize' },
        //         { title: 'mysql', description: '将采用mysql数据库进行开发', value: 'mysql' },
        //         { title: 'mongoose', description: '这是一个mongdb的ORM框架', value: 'mongoose' },
        //         { title: 'redis', description: '将采用redi内存数据库进行开发', value: 'redis' },

        //     ],
        //     initial: 0,
        // }
    ])
    /** @type {string} app.js模板 */
    const appJSTempalte = `
const express = require('express')
const path = require('path')
/* 日志 */
const logger = require('morgan')
/* http 和 https */
const http = require('http')
/* 采用环境变量 */
const dotenv = require('dotenv')
dotenv.config()
/* 跨域配置 */
const cors = require('cors')

/* 路由导入 */
const test = require('./routes/test')

class App {
    constructor(port) {
        this.port = process.env.PORT || port || '3000'
        this.app = express()
        this.server = http.createServer(this.app)

        /* 初始化 */
        this.initMiddleWare()
        this.initRoutes()
        this.startListent()
        this.ininIndex()
        this.catch404()
    }
    /**
     * 初始化中间件
     *
     * @memberof App
     */
    initMiddleWare() {
        /* 开启之后路径请求将不会转为小写 */
        this.app.set('case sensitive routing', true);
        /* 日志 */
        this.app.use(logger('dev'))
        /* 请求体解析 */
        this.app.use(express.urlencoded({ extended: false }))
        this.app.use(express.json())
        /* 开放静态目录 http://127.0.0.1:5000/public/  */
        this.app.use('/public', express.static(path.join(__dirname, '/public')))
        /* 开放apidoc http://127.0.0.1:5000/apidoc/  */
        this.app.use('/apidoc', express.static(path.join(__dirname, 'apidoc')))
        /* 允许跨域 */
        this.app.use(cors())
    }
    /**
     * 初始化路由
     *
     * @memberof App
     */
    initRoutes() {
        this.app.use(test)
    }
    /**
     * 监听端口
     *
     * @memberof App
     */
    startListent() {
        this.server.listen(this.port, () => {
            console.log('-----------apprunning---------')
            console.log('http://127.0.0.1:' + this.port)
            console.log('------------------------------')
        })
    }
    ininIndex() {
        this.app.get('/', (req, res, next) => {
            res.json({
                code: 200,
                message: '服务正常运行。。。'
            })
        })
    }
    /**
     * 捕获404
     *
     * @memberof App
     */
    catch404() {
        this.app.use((req, res, next) => {
            res.json({
                code: 404,
                message: '当前访问的路径不存在'
            })
        })
    }
}
new App()
`
    /** @type {string} package.json模板 */
    const packageTempalte = `
{
    "name": "${appName}",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
      "test": "echo \\"Error: no test specified\\" && exit 1",
      "dev": "nodemon app",
      "apidoc": "apidoc -i routes/ -o apidoc"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
      "apidoc": "^0.28.1",
      "cors": "^2.8.5",
      "dotenv": "^10.0.0",
      "express": "^4.17.1",
      "joi": "^17.4.1",
      "morgan": "^1.10.0",
      "nodemon": "^2.0.12"
    }
  }

`
    /** @type {string} 环境变量模板 */
    const envTempalte = `
PORT = '5000'
`
    /** @type {string} apidoc.json 模板 */
    const apidocjsonTempalte = `
{
    "name": "appName",
    "version": "1.0.0",
    "description": "可以到apidoc.json中进行更改",
    "title": "appName",
    "url": "http://127.0.0.1:5000"
}
`
    /** @type {string} readme.md 模板 */
    const readmeTempalte = `
# 目录解析

## 运行 npm install
- 安装所需依赖

## apidoc api接口文档
- \`npm run apidoc\` 生成接口文档
- 注解模板
\`\`\`js
/**
 * 
 * @api {get} /testGET 测试get
 * @apiName 测试get
 * @apiGroup test
 * @apiVersion  1.0.0
 * 
 * 
 * @apiParam  {String} test 测试参数
 * 
 * @apiSuccess (200) {number} code 200
 * @apiSuccess (200) {string} message 测试成功
 * 
 * @apiParamExample  {json} Request-Example:
 * {
 *     test : '这是参数呀',
 * }
 * 
 * 
 * @apiSuccessExample {json} Success-Response:
 * {
 *     code : 200,
 *     message : '测试成功'
 * }
 * 
 * 
 */
router.get('/testGET', testController.api1)
\`\`\`

## controller 控制层
- 基本逻辑

## routes 路由列表

## .env 全局环境变量
- process.env 进行调用

## apidoc.json api文档配置文件
- 详细配置参考 apidoc npm

## app.js app入口
- npm run dev 开始热更新

## package.js 所需包
`
    /** @type {string} 测试路由模板 */
    const routeTestTemplate = `
const express = require('express')
const router = express.Router()
const testController = require('../controller/test')


/**
 * 
 * @api {get} /testGET 测试get
 * @apiName 测试get
 * @apiGroup test
 * @apiVersion  1.0.0
 * 
 * 
 * @apiParam  {String} test 测试参数
 * 
 * @apiSuccess (200) {number} code 200
 * @apiSuccess (200) {string} message 测试成功
 * 
 * @apiParamExample  {json} Request-Example:
 * {
 *     test : '这是参数呀',
 * }
 * 
 * 
 * @apiSuccessExample {json} Success-Response:
 * {
 *     code : 200,
 *     message : '测试成功'
 * }
 * 
 * 
 */
router.get('/testGET', testController.api1)


/**
 * 
 * @api {post} /testPOST 测试呀POST
 * @apiName 测试post
 * @apiGroup test
 * @apiVersion  1.0.0
 * 
 * 
 * @apiParam  {String} test 这是参数呀
 * 
 * @apiSuccess (200) {number} code 200
 * @apiSuccess (200) {string} message 测试成功
 * 
 * @apiParamExample  {json} Request-Example:
 * {
 *     test : 参数,
 * }
 * 
 * 
 * @apiSuccessExample {json} Success-Response:
 * {
 *     code : 200,
 *     message : ‘测试成功’
 * }
 * 
 * 
 */
router.post('/testPOST', testController.api2)
module.exports = router
 `
    /** @type {string} 测试路由控制层模板 */
    const controllerTempalte = `
/* 校验工具 */
const Joi = require('joi')


const test = {}
test.api1 = async (req, res) => {
    /* 字段校验 */
    const schema = Joi.object({
        test: Joi.string().min(3).max(30).required().error(new Error('必须传入test')),
        // 校验密码
        // password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{6,30}$')).required().error(new Error('请传入正确的密码'))
        // 校验邮箱
        // email: Joi.string().email().required(),  
    })

    let { value, error } = await schema.validate(req.query)
    if (error) {
        res.json({
            code: 404,
            message: error.toString().split(': ')[1],
            data: []
        })
    } else {
        res.json({
            code: 200,
            message: '测试GET成功',
            data: {
                param: value
            }
        })
    }
}
test.api2 = (req, res) => {
    res.json({
        code: 200,
        message: '测试POST成功',
        data: {
            body: req.body
        }
    })
}
module.exports = test
`

    /**
     * 根据模板创建node app 目录结构
     *
     */
    const createFiles = async () => {

        /** @type {object} 模板对象 */
        const files = {
            [appName]: '',
            [`${appName}/app.js`]: appJSTempalte,
            [`${appName}/package.json`]: packageTempalte,
            [`${appName}/.env`]: envTempalte,
            [`${appName}/apidoc.json`]: apidocjsonTempalte,
            [`${appName}/readme.md`]: readmeTempalte,
            [`${appName}/routes/`]: '',
            [`${appName}/routes/test.js`]: routeTestTemplate,
            [`${appName}/controller/`]: '',
            [`${appName}/controller/test.js`]: controllerTempalte,
            [`${appName}/public/`]: '',
        }
        /** @type {*} 创建进度条样式 正在创建文件 [#          ] 0 / 10 app.js */
        const bar = new ProgressBar('正在创建文件 [:bar] :current / :total :file', {
            complete: '#',
            incomplete: ' ',
            total: Object.keys(files).length
        })
        /**
         * 睡眠，以免进度条过快
         *
         * @param {number} time 睡眠时间  毫秒
         * @return {*} 
         */
        const sleep = (time) => {
            return new Promise((res) =>
                setTimeout(res, time)
            )
        }
        for (const key in files) {
            /* 进度条后面的文件路径 */
            bar.tick({
                file: key
            })
            /* 为空创建文件夹，否则创建文件 */
            files[key] == '' ? fs.mkdirSync(key) : fs.writeFileSync(key, files[key])
            await sleep(100)
        }
        for (const key in files) {
            console.log(chalk.green('√'), `created --> ${key}`);
        }
        console.log(chalk.green(`--------------------------tips--------------------------`));
        console.log(chalk.green(`                                   
            1.cd ${appName} 切换到${appName}目录
            2.运行 npm install 安装依赖
            3.运行 npm run apidoc 生成api文档
        `));
        console.log(chalk.green(`--------------------------------------------------------`));
    }
    createFiles()
    // 退出进程
    // process.exit(0)
    // TODO 尝试给出数据库模块 sequelize-orm

}
getAppOptions()
